home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume89 / intuitin / qmenu.1 < prev    next >
Text File  |  1989-03-08  |  36KB  |  1,142 lines

  1. Path: xanth!lll-winken!csd4.milw.wisc.edu!mailrus!bbn!ulowell!page
  2. From: page@swan.ulowell.edu (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v89i027:  qmenu - quick menu creation code
  5. Message-ID: <12039@swan.ulowell.edu>
  6. Date: 8 Mar 89 02:13:36 GMT
  7. Organization: University of Lowell, Computer Science Dept.
  8. Lines: 1131
  9. Approved: page@swan.ulowell.edu
  10.  
  11. Submitted-by: well!shf (Stuart H. Ferguson)
  12. Posting-number: Volume 89, Issue 27
  13. Archive-name: intuition/qmenu.1
  14.  
  15. [uuencoded test program included.  ..Bob]
  16.  
  17. #    This is a shell archive.
  18. #    Remove everything above and including the cut line.
  19. #    Then run the rest of the file through sh.
  20. #----cut here-----cut here-----cut here-----cut here----#
  21. #!/bin/sh
  22. # shar:    Shell Archiver
  23. #    Run the following text with /bin/sh to create:
  24. #    ReadMe
  25. #    Makefile
  26. #    qmenu.c
  27. #    qmenu.h
  28. #    mtst.c
  29. #    mtst.uu
  30. # This archive created: Tue Mar  7 21:10:08 1989
  31. cat << \SHAR_EOF > ReadMe
  32. IntuiTools: qmenu
  33.  
  34. Here's a little quick menu creation code I put together for making menus
  35. for Modeler 3D.  The instructions are in the comments.  Included are the
  36. main code itself in a module and an example program.  The code compiles
  37. under Manx 3.6, but I can't see why I wouldn't compile equally well 
  38. elsewhere.
  39.  
  40. Enjoy,
  41.  
  42.     Stuart Ferguson        1/89
  43.     (shf@well.UUCP)
  44.  
  45.     123 James Ave.
  46.     Redwood City, Ca.
  47.         94062
  48. SHAR_EOF
  49. cat << \SHAR_EOF > Makefile
  50. # Quickmenu Module and test program (mtst).
  51. # Manx 3.6 Makefile.
  52.  
  53. mtst : mtst.o qmenu.o
  54.     ln mtst.o qmenu.o -lc -o $@
  55.  
  56. qmenu.o : qmenu.c qmenu.h
  57.     cc qmenu.c -o $@
  58.  
  59. mtst.o : mtst.c qmenu.h
  60.     cc mtst.c -o $@
  61. SHAR_EOF
  62. cat << \SHAR_EOF > qmenu.c
  63. /*
  64.  * Quick Menu Package -- An easy way to make simple (but nice) menus.
  65.  *
  66.  * The client programmer will generally use the GenMenu()/FreeMenu() 
  67.  * interface which creates and frees a whole menu strip.  A menu strip
  68.  * -- both the main strip and menu item strips -- is defined by a
  69.  * NewMenu struct.  Each NewMenu struct (defined in qmenu.h) is just a
  70.  * pointer to an array of strings and a pointer to an array of
  71.  * NewMenu's.  The elements of the array of NewMenu's are paired with the
  72.  * strings in the array and represent the sub menus for that string.
  73.  * The string array is terminated with a null pointer.
  74.  *
  75.  * The package tries to do nice things, like automatically formatting
  76.  * the menu strings into blocks with their command keys, and placing
  77.  * markers pointing to subitem stips.  The strings for the menu items
  78.  * can contain special control codes to control the optional 
  79.  * characteristics of items.  Special codes come at the front of item
  80.  * strings and are delimited with a special character (SPECIAL,
  81.  * defined as '!' by default) and are listed briefly below:
  82.  *
  83.  *    c    Checkmark item
  84.  *    t    Checkmark toggle
  85.  *    +    Checkmark checked
  86.  *    b    Highlight box
  87.  *    n    Highlight none
  88.  *    d    Disabled
  89.  *    =C    Set command key to "C"
  90.  *    0101...    Set item exclude mask
  91.  *
  92.  * Any number of 1's and 0's after the special character will set the
  93.  * Mutual exclude bits for that item in the order they occur.  So the
  94.  * first 1 or 0 will set bit 0 of the exclude mask, the second will
  95.  * set bit 1, etc.  Any unset will be 0.
  96.  *
  97.  * Additionally, if the item string is "-", the item will be 
  98.  * a non-selectable horizontal line (a "rule") that can be used to 
  99.  * visually group similar items in the menu strip.  There only need
  100.  * to be NewMenu structs in the array for text menu items, not rules,
  101.  * but don't forget to account for rules when counting MenuItem's
  102.  * since they take a slot.
  103.  *
  104.  *
  105.  * GenMenu() takes a pointer to a NewMenu struct and will create a main
  106.  * Menu strip from the strings in the struct, with menu items from the
  107.  * associated NewMenu's.  It returns a pointer to a Menu struct which is
  108.  * the first element in the list for this strip.
  109.  *
  110.  * GenStrip() takes a pointer to an array of strings and creates a
  111.  * top-level set of Menu structs for the main menu strip.
  112.  *
  113.  * FreeMenu() frees a Menu strip created with either GenMenu() or
  114.  * GenStrip().
  115.  *
  116.  * GenItems() takes a pointer to a NewMenu struct and creates a single
  117.  * list of MenuItem's from the description.  It also takes an X and Y
  118.  * offset for all the elements in the list.
  119.  *
  120.  * FreeMItem() frees structures created by the above function.
  121.  *
  122.  * AttachSubMenu() takes a single MenuItem and a NewMenu struct and
  123.  * attaches the MenuItems created from that NewMenu struct to the
  124.  * parent MenuItem.  The parent should also have been created with
  125.  * GenItems() in order to work correctly.  AttachSubMenu() places a
  126.  * little maker on the parent item to show that it has subitems.  It
  127.  * returns 1 for sucess and 0 for failure.
  128.  *
  129.  * -- WARNING:
  130.  *
  131.  * The client programmer is completely responsible for keeping the
  132.  * menus within the bounds of the screen and for keeping within the
  133.  * limits of Intuition.  The menu structures will not adjust as they
  134.  * hit the borders of the screen (which might be a nice enhancement).
  135.  * The strings in the NewMenu structures cannot be changed or deleted
  136.  * while the Menus are in use, although they can be used to create
  137.  * multiple Menus from the same strings.
  138.  *
  139.  **
  140.  * This code can be used and modified freely.  Do let me know of any
  141.  * improvements or enhancements you may add, and be sure to give credit
  142.  * where credit is due (in the comments) if you redistribute this code.
  143.  *
  144.  *    Stuart Ferguson        1/89
  145.  *    (shf@well.UUCP)
  146.  */
  147. #include <intuition/intuition.h>
  148. #include "qmenu.h"
  149.  
  150. /*
  151.  * Some useful macros for allocating and freeing structures and
  152.  * arrays of structures.
  153.  */
  154. #define NEW(typ)    (typ*)AllocMem((long)sizeof(typ),0L)
  155. #define FREI(p)        FreeMem(p,(long)sizeof(*p))
  156.  
  157. #define NEW_N(typ,n)    (typ*)AllocMem((long)((n)*sizeof(typ)),0L)
  158. #define FREI_N(p,n)    FreeMem(p,(long)((n)*sizeof(*p)))
  159.  
  160. char * AllocMem();
  161.  
  162. /*
  163.  * Definitions for formatting the menus.  Glossary:
  164.  *
  165.  *    TEXTCOLOR    - color of the text items in the menus.
  166.  *    MARKCOLOR    - color of the subitem marker.
  167.  *    RULECOLOR    - color of the horizontal lines in the menus.
  168.  *    RULEHEIGHT    - vertical thickness of the horizontal rules.
  169.  *    RULEGAP        - vertical blank space around the rules.
  170.  *    RULEMARGIN    - horizontal blank space around the rules.
  171.  *    TEXTGAP        - vertical blank space around the text items.
  172.  *    TEXTMARGIN    - horizontal blank space around the text items.
  173.  *    MAINWID        - width of the text font on the main menu.
  174.  *    MAINGAP        - spacing between items on the main menu strip.
  175.  *    SUBINDENT    - overlap between items and their subitems.
  176.  *    SUBDOWN        - vertical shift between items and their subitems.
  177.  */
  178. #define TEXTCOLOR    2
  179. #define MARKCOLOR    3
  180. #define RULECOLOR    0
  181. #define RULEHEIGHT    2
  182. #define RULEGAP        4
  183. #define RULEMARGIN    10
  184. #define TEXTGAP        2
  185. #define TEXTMARGIN    4
  186. #define MAINWID        10
  187. #define MAINGAP        10
  188. #define SUBINDENT    18
  189. #define SUBDOWN        0
  190.  
  191. /*
  192.  * Escape character for special control codes in text items strings.
  193.  */
  194. #define SPECIAL        '!'
  195.  
  196. /*
  197.  * The extern "ta" is set by the client program for
  198.  * the font to use for these menus.
  199.  */
  200. extern struct TextAttr ta;
  201.  
  202. /*
  203.  * Generic templates to use for creating the dynamic menu structures. 
  204.  */
  205. static struct IntuiText
  206.   generic_itext = {TEXTCOLOR, 0, JAM1, TEXTMARGIN/2, TEXTGAP/2, &ta,NULL,NULL},
  207.   generic_smark = {MARKCOLOR, 0, JAM1, 0, TEXTGAP/2, &ta, (UBYTE *) ";", NULL};
  208.  
  209. static struct Menu
  210.   generic_main = {NULL, 0, 0, 0, 10, MENUENABLED, NULL, NULL};
  211.  
  212. static struct MenuItem
  213.   generic_mitem = {
  214.      NULL, 0, 0, 0, 0,
  215.      ITEMTEXT | ITEMENABLED | HIGHCOMP,
  216.      0, NULL, NULL, 0, NULL, 0
  217. };
  218.  
  219. /* Image struct with no imagery for the horizontal lines.
  220.  */
  221. static struct Image
  222.   generic_hrule = {0, 0, 1, RULEHEIGHT, 2, NULL, 0, RULECOLOR, NULL};
  223.  
  224. static struct MenuItem
  225.   generic_hitem = {
  226.      NULL, RULEMARGIN/2, 0, 0, 0,
  227.      ITEMENABLED | HIGHNONE,
  228.      0, NULL, NULL, 0, NULL, 0
  229. };
  230.  
  231.  
  232. /*
  233.  * Takes an array of strings and associated array of NewMenu structs
  234.  * (as a single NewMenu struct) and constructs a menu strip from the
  235.  * descripton.  This is the main high-level call that most clients
  236.  * will make.
  237.  */
  238. struct Menu * GenMenu (nmen)
  239.     register struct NewMenu *nmen;
  240. {
  241.     register short  i, ok, n;
  242.     register struct Menu *mm;
  243.     register struct MenuItem *mi;
  244.  
  245.     /* Count menus to be generated and create top level structure.
  246.      */
  247.     for (n = 0; nmen->str[n]; n++) ;
  248.     mm = GenStrip (nmen->str);
  249.     if (!mm) return NULL;
  250.  
  251.     /* Create the item strip for each main menu and attach to the
  252.      * top level Menu structure.  Any failure causes the whole
  253.      * thing to crumble to dust.
  254.      */
  255.     ok = 1;
  256.     nmen = nmen->submenu;
  257.     for (i = 0; i < n; i++) {
  258.         if (nmen->str) {
  259.             mi = GenItems (nmen, 0L, 0L);
  260.             mm[i].FirstItem = mi;
  261.             ok &= (mi != NULL);
  262.         }
  263.         nmen ++;
  264.     }
  265.     if (!ok) {
  266.         FreeMenu (mm);
  267.         return NULL;
  268.     }
  269.     return mm;
  270. }
  271.  
  272.  
  273. /*
  274.  * Generate a menu strip.  Just creates the top level Menu structures,
  275.  * linked together and intialized.  Takes an array of pointers to
  276.  * strings.
  277.  */
  278. struct Menu * GenStrip (str)
  279.     char **str;
  280. {
  281.     register short  i, x, num;
  282.     register struct Menu *mm, *m;
  283.  
  284.     /*
  285.      * Create enough struct Menu's for the menu strip. 
  286.      */
  287.     for (num = 0; str[num]; num++) ;
  288.     mm = NEW_N (struct Menu, num);
  289.     if (!mm) return NULL;
  290.  
  291.     /*
  292.      * Init the structures using the generic Menu struct as a template.
  293.      * NOTE: the size of the font for these item labels is unknown for
  294.      *       windows on the Workbench screen, so a size should be used
  295.      *       that will work with 60 & 80 column fonts. 
  296.      */
  297.     x = 0;
  298.     for (i = 0; i < num; i++) {
  299.         m = &mm[i];
  300.         *m = generic_main;
  301.         m->LeftEdge = x;
  302.         m->Width = strlen (str[i]) * MAINWID + TEXTMARGIN;
  303.         x += m->Width + MAINGAP;
  304.         m->MenuName = str[i];
  305.         m->NextMenu = m + 1;
  306.     }
  307.     mm[num - 1].NextMenu = NULL;
  308.     return mm;
  309. }
  310.  
  311.  
  312. /*
  313.  * Attach a submenu to a MenuItem.  Takes the parent MenuItem and a
  314.  * NewMenu structure that will be attached as a sub-menu.  
  315.  * Attaches a ";" mark at the end of the parent item and calls
  316.  * GenItems() to create the sub-menu strip.
  317.  */
  318. BOOL AttachSubMenu (mi, nmen)
  319.     register struct MenuItem    *mi;
  320.     struct NewMenu            *nmen;
  321. {
  322.     register struct IntuiText *it;
  323.  
  324.     /* Create an IntuiText with the marker and position it
  325.      * at the right edge of the item.
  326.      */
  327.     if (!(it = NEW (struct IntuiText))) return FALSE;
  328.     *it = generic_smark;
  329.     it->LeftEdge = mi->Width - IntuiTextLength (it) - 2;
  330.  
  331.     /* Create the subitem structure and attach to the main item.
  332.      */
  333.     if (!(mi->SubItem = GenItems
  334.           (nmen, (LONG) (mi->Width - SUBINDENT), (LONG) SUBDOWN))) {
  335.         FREI (it);
  336.         return FALSE;
  337.     }
  338.  
  339.     /* Only if it all worked attach the new text structure.
  340.      */
  341.     ((struct IntuiText *) mi->ItemFill)->NextText = it;
  342.     return TRUE;
  343. }
  344.  
  345.  
  346. /*
  347.  * Takes the given menu text item and skips past the special control
  348.  * codes while adjusting the associated MenuItem appropriately.
  349.  * Special codes are in the form of "!x", where "x" is:
  350.  *
  351.  *    c    Checkmark item
  352.  *    t    Checkmark toggle
  353.  *    b    Highlight box
  354.  *    n    Highlight none
  355.  *    d    Disabled
  356.  *    +    Checkmark checked
  357.  *    =C    Set command key to "C"
  358.  *    1010...    Set item exclude mask
  359.  *
  360.  * Takes the mostly defined MenuItem and diddles it.  Returns a pointer
  361.  * to the item text with control codes stripped.
  362.  */
  363. static UBYTE * ProcessSpecialStuff (str, mi)
  364.     char *str;
  365.     struct MenuItem *mi;
  366. {
  367.     register LONG    x;
  368.     register int    i;
  369.  
  370.     while (*str == SPECIAL) {
  371.         switch (*++str) {
  372.             case 'c':
  373.             mi->Flags |= CHECKIT;
  374.             break;
  375.             case 't':
  376.             mi->Flags |= CHECKIT | MENUTOGGLE;
  377.             break;
  378.             case 'b':
  379.             mi->Flags &= ~HIGHFLAGS;
  380.             mi->Flags |= HIGHBOX;
  381.             break;
  382.             case 'n':
  383.             mi->Flags &= ~HIGHFLAGS;
  384.             mi->Flags |= HIGHNONE;
  385.             break;
  386.             case 'd':
  387.             mi->Flags &= ~ITEMENABLED;
  388.             break;
  389.             case '+':
  390.             mi->Flags |= CHECKIT | CHECKED;
  391.             break;
  392.             case '=':
  393.             mi->Flags |= COMMSEQ;
  394.             mi->Command = *++str;
  395.             break;
  396.             case '0':
  397.             case '1':
  398.             x = 0;
  399.             i = 0;
  400.             while (*str == '0' || *str == '1')
  401.                 x += (*str++ - '0') << (i++);
  402.             mi->MutualExclude = x;
  403.             str--;
  404.             break;
  405.         }
  406.         str++;
  407.     }
  408.     return (UBYTE*) str;
  409. }
  410.  
  411.  
  412. /*
  413.  * Construct a basic item list for a menu.  Takes a NewMenu structure
  414.  * which contains a pointer to an array of pointers to strings and a 
  415.  * pointer to an array of NewMenu structures.  The strings contain the
  416.  * item text for each menu plus optional special control codes.  If the
  417.  * string is "-", the item will be a horizontal rule rather than a text
  418.  * item.  The NewMenu structures, if not NULL, are the sub-menu's for
  419.  * each menu in the array.
  420.  * "x" and "y" are the horizontal and vertical offsets of this set of
  421.  * MenuItems.  These are set by AttachSubMenu() for positioning submenus
  422.  * under their parent items.
  423.  */
  424. struct MenuItem *GenItems (nmen, x, y)
  425.     struct NewMenu *nmen;
  426.     LONG    x, y;
  427. {
  428.     register struct MenuItem *mi, *cmi;
  429.     register struct IntuiText *itext;
  430.     struct Image   *img;
  431.     register short  i, len, max;
  432.     short           n;
  433.     struct NewMenu *sub;
  434.  
  435.     /* Count menu items (n) and allocate an array for the strip.
  436.      */
  437.     for (n = 0; nmen->str[n]; n++) ;
  438.     if (!(mi = NEW_N (struct MenuItem, n))) return NULL;
  439.  
  440.     /* Counts the number of rules in the menu ("-" strings)
  441.      * and allocates the structures for the lines and the text items.
  442.      */
  443.     max = 0;
  444.     for (i = 0; i < n; i++) max += (*nmen->str[i] == '-');
  445.     if (n - max)
  446.         if (!(itext = NEW_N (struct IntuiText, n - max))) {
  447.             FREI_N (mi, n);
  448.             return NULL;
  449.         }
  450.     if (max)
  451.         if (!(img = NEW_N (struct Image, max))) {
  452.             FREI_N (mi, n);
  453.             if (n - max) FREI_N (itext, n - max);
  454.             return NULL;
  455.         }
  456.  
  457.     /* Loop through text menu items and initialize the
  458.      * associated IntuiText structures.  Compute the maximum
  459.      * width of the menu taking command keys into account while
  460.      * assigning all the other parts of the text MenuItem's.
  461.      */
  462.     max = 0;
  463.     for (i = 0; i < n; i++) {
  464.         if (*nmen->str[i] == '-') continue;    /* skip rules */
  465.  
  466.         /* Init the text MenuItem to point to the assocd IntuiText.
  467.          */
  468.         cmi = &mi[i];
  469.         *cmi = generic_mitem;
  470.         cmi->ItemFill = (APTR) itext;
  471.  
  472.         /* Init the IntuiText and adjust the MenuItem from the
  473.          * flags set in the menu text string.
  474.          */
  475.         *itext = generic_itext;
  476.         itext->IText = ProcessSpecialStuff (nmen->str[i], cmi);
  477.  
  478.         /* Make a first cut at measuring the length of the item.
  479.          */
  480.         len = IntuiTextLength (itext) + TEXTMARGIN;
  481.  
  482.         /* If command key set, add to length.
  483.          */
  484.         if (cmi->Flags & COMMSEQ) len += COMMWIDTH + MAINWID;
  485.  
  486.         /* If this is a checkmark item, shift the text over to
  487.          * make room and add that to the length.
  488.          * Compute the max length.
  489.          */
  490.         if (cmi->Flags & CHECKIT) {
  491.             itext->LeftEdge += CHECKWIDTH;
  492.             len += CHECKWIDTH;
  493.         }
  494.         if (len > max) max = len;
  495.         itext ++;
  496.     }
  497.  
  498.     /* Secondary assignment loop.  Position the text MenuItems and
  499.      * init the horizontal lines.
  500.      */
  501.     for (i = 0; i < n; i++) {
  502.         cmi = &mi[i];
  503.  
  504.         if (*nmen->str[i] != '-') {
  505.             cmi->LeftEdge = x;
  506.             cmi->TopEdge = y;
  507.             cmi->Width = max;
  508.             cmi->Height = ta.ta_YSize + TEXTGAP;
  509.             y += cmi->Height;
  510.         } else {
  511.  
  512.             /* Rule items point to their Image structure
  513.              * and are just a little narrower than the
  514.              * menu itself.
  515.              */
  516.             *img = generic_hrule;
  517.             img->Width = max - RULEMARGIN;
  518.             *cmi = generic_hitem;
  519.             cmi->TopEdge = y + RULEGAP/2;
  520.             y += RULEHEIGHT + RULEGAP;
  521.             cmi->ItemFill = (APTR) img;
  522.             img ++;
  523.         }
  524.         cmi->NextItem = cmi + 1;
  525.     }
  526.     mi[n - 1].NextItem = NULL;
  527.  
  528.     /* Attach submenu's, if any.
  529.      */
  530.     if (!(sub = nmen->submenu)) return mi;
  531.  
  532.     /* Use "max" as a flag for the success of the attachments.
  533.      */
  534.     max = 1;
  535.     for (i = 0; i < n; i++) {
  536.         if (*nmen->str[i] == '-') continue;
  537.         if (sub->str)
  538.             max &= AttachSubMenu (&mi[i], sub);
  539.         sub ++;
  540.     }
  541.     if (!max) {
  542.         FreeMItem (mi);
  543.         return NULL;
  544.     }
  545.     return mi;
  546. }
  547.  
  548.  
  549. /*
  550.  * Free a Menu structure created by GenStrip() that has items 
  551.  * created with GenItems().
  552.  */
  553. void FreeMenu (mm)
  554.     struct Menu    *mm;
  555. {
  556.     register short  i;
  557.     register struct Menu *t;
  558.  
  559.     i = 0;
  560.     for (t = mm; t; t = t->NextMenu) {
  561.         if (t->FirstItem) FreeMItem (t->FirstItem);
  562.         i++;
  563.     }
  564.     FREI_N (mm, i);
  565. }
  566.  
  567.  
  568. /*
  569.  * Free a MenuItem structure created by GenItems().
  570.  */
  571. void FreeMItem (mi)
  572.     register struct MenuItem *mi;
  573. {
  574.     register short  nit, nimg;
  575.     register struct MenuItem *c;
  576.     register struct IntuiText *it = NULL, *it1;
  577.     struct Image   *img = NULL;
  578.  
  579.     /* Scan the MenuItem structures and count the number of images
  580.      * and IntuiText structures.  Find the pointer to the first of
  581.      * each structure in the set.  That will be the first element
  582.      * in the array that was allocated as a unit.
  583.      */
  584.     nit = nimg = 0;
  585.     for (c = mi; c; c = c->NextItem) {
  586.         if (c->SubItem) FreeMItem (c->SubItem);
  587.         if (c->Flags & ITEMTEXT) {
  588.             it1 = (struct IntuiText *) c->ItemFill;
  589.             if (!it) it = it1;
  590.             nit++;
  591.  
  592.             /* Free the subitem marker, if any.
  593.              */
  594.             if (it1->NextText) FREI (it1->NextText);
  595.         } else {
  596.             if (!img) img = (struct Image *) c->ItemFill;
  597.             nimg++;
  598.         }
  599.     }
  600.  
  601.     /* Free the arrays of structures of images and texts, as
  602.      * well as the main array of MenuItem structures themselves.
  603.      */
  604.     if (nit) FREI_N (it, nit);
  605.     if (nimg) FREI_N (img, nimg);
  606.     FREI_N (mi, nit + nimg);
  607. }
  608. SHAR_EOF
  609. cat << \SHAR_EOF > qmenu.h
  610. struct NewMenu {
  611.     char **str;
  612.     struct NewMenu *submenu;
  613. };
  614.  
  615.  
  616. struct Menu *GenMenu();
  617. struct Menu *GenStrip();
  618. struct MenuItem *GenItems();
  619. LONG AttachSubItem();
  620. void FreeMenu();
  621. void FreeMItem();
  622. SHAR_EOF
  623. cat << \SHAR_EOF > mtst.c
  624. /*
  625.  * Example program for using quick menu package.  Contains the necessary
  626.  * declarations for a simple menu strip which it creates and destroys after
  627.  * letting the user play with it.
  628.  */
  629. #include <intuition/intuition.h>
  630. #include "qmenu.h"
  631.  
  632.  
  633. #define NILSUB    {NULL,NULL}
  634.  
  635. /*
  636.  * String arrays get defined in sort-of reverse order.
  637.  * I.e. the subitems get defined before the parent items.
  638.  * (One rule is that menu items that cause a Requester to
  639.  * appear are followed by "...".)
  640.  * The string arrays themselves are terminated by a null 
  641.  * string pointer.
  642.  */
  643. char *mpo_str[] = {
  644.     "!=ORaw Text...",
  645.     "Processed Text...",
  646.     "Drawing...",
  647.     "Picture...",
  648.     "Old Settings...",
  649.     NULL };
  650.  
  651. char *mps_str[] = {
  652.     "!=TText...",
  653.     "!=DDrawing...",
  654.     "Picture...",
  655.     NULL };
  656.  
  657. char *mp_str[] = {
  658.     "!=NNew...",
  659.     "Open",
  660.     "!=SSave...",
  661.     "Save as",
  662.     "Print...",
  663.     "Save Settings",
  664.     "About...",
  665.     "-",
  666.     "!bQuit...",
  667.     NULL };
  668.  
  669. /* Array of NewMenu structs to go with the above text items.
  670.  * Needs to be a one-to-one correspondence between text items
  671.  * (not rules) and NewMenu structs.
  672.  */
  673. struct NewMenu mp_sub[] = {
  674.     NILSUB,
  675.     { mpo_str, NULL },
  676.     NILSUB,
  677.     { mps_str, NULL },
  678.     NILSUB,
  679.     NILSUB,
  680.     NILSUB,
  681.     NILSUB
  682. };
  683.  
  684. char *mes_str[] = {
  685.     "!+!0111!=PPlain",
  686.     "!c!1!=BBold",
  687.     "!c!1!=IItalic",
  688.     "!c!1!=UUnderline",
  689.     NULL };
  690.  
  691. char *me_str[] = {
  692.     "!=QUndo",
  693.     "-",
  694.     "!=ZDelete",
  695.     "!=XCut",
  696.     "!=CCopy",
  697.     "!=VPaste",
  698.     "-",
  699.     "Set Font...",
  700.     "Set Style",
  701.     NULL };
  702.  
  703. struct NewMenu me_sub[] = {
  704.     NILSUB,
  705.     NILSUB,
  706.     NILSUB,
  707.     NILSUB,
  708.     NILSUB,
  709.     NILSUB,
  710.     { mes_str, NULL }
  711. };
  712.  
  713. char *mdz_str[] = {
  714.     "!=>In",
  715.     "!=<Out",
  716.     "!=MManual",
  717.     NULL };
  718.  
  719. char *mdv_str[] = {
  720.     "!+!tText",
  721.     "!+!tLines",
  722.     "!+!tImages",
  723.     "!+!tBoxes",
  724.     "!+!tLabels",
  725.     NULL };
  726.  
  727. char *mds_str[] = {
  728.     "Interlace",
  729.     "Non-interlace",
  730.     "Workbench",
  731.     NULL };
  732.  
  733. char *md_str[] = { 
  734.     "Zoom",
  735.     "!=AAuto Scale",
  736.     "-",
  737.     "!c!tCoordinates",
  738.     "Visible",
  739.     "-",
  740.     "Screen Colors...",
  741.     "Screen Type",
  742.     NULL };
  743.  
  744. struct NewMenu md_sub[] = {
  745.     { mdz_str, NULL },
  746.     NILSUB,
  747.     NILSUB,
  748.     { mdv_str, NULL },
  749.     NILSUB,
  750.     { mds_str, NULL }
  751. };
  752.  
  753. char *mhc_str[] = {
  754.     "Plot...",
  755.     "Set...",
  756.     "Lay in...",
  757.     NULL };
  758.  
  759. char *mhw_str[] = {
  760.     "!+!0111111Full Impulse",
  761.     "!c!1011111!=1Warp 1",
  762.     "!c!1101111!=2Warp 2",
  763.     "!c!1110111!=3Warp 3",
  764.     "!c!1111011!=4Warp 4",
  765.     "!c!1111101!=5Warp 5",
  766.     "!c!1111110Space Normal",
  767.     NULL };
  768.  
  769. char *mhp_str[] = {
  770.     "Stun",
  771.     "Kill",
  772.     "Maim",
  773.     "Burn",
  774.     "Overload",
  775.     "Ineffective",
  776.     "Burn Out",
  777.     NULL };
  778.  
  779. char *mh_str[] = {
  780.     "New Course",
  781.     "Speed",
  782.     "Standard Orbit",
  783.     "Tractor Beam...",
  784.     "Lock Phasers",
  785.     "-",
  786.     "\"Make It So.\"",
  787.     NULL };
  788.  
  789. struct NewMenu mh_sub[] = {
  790.     { mhc_str, NULL },
  791.     { mhw_str, NULL },
  792.     NILSUB,
  793.     NILSUB,
  794.     { mhp_str, NULL },
  795.     NILSUB
  796. };
  797.  
  798. char *mt_str[] = {
  799.     "Hammer",
  800.     "Screwdriver",
  801.     "Chisel",
  802.     "Knife",
  803.     "Felt Pen",
  804.     "Air Freshener",
  805.     "-",
  806.     "Hammer Size...",
  807.     "Screw Type...",
  808.     "Pine Scent...",
  809.     NULL };
  810.  
  811. char *mm_str[] = {
  812.     "Rotate...",
  813.     "Spin...",
  814.     "Turn Around...",
  815.     "Flip Out...",
  816.     "Randomize...",
  817.     "Energize...",
  818.     "Simplify",
  819.     "Complexify",
  820.     NULL };
  821.  
  822. char *main_str[] = {
  823.     "Project",
  824.     "Edit",
  825.     "Display",
  826.     "Tools",
  827.     "Helm",
  828.     "Modify",
  829.     NULL };
  830.  
  831. struct NewMenu main_sub[] = {
  832.     { mp_str, mp_sub },
  833.     { me_str, me_sub },
  834.     { md_str, md_sub },
  835.     { mt_str, NULL },
  836.     { mh_str, mh_sub },
  837.     { mm_str, NULL }
  838. };
  839.  
  840. struct NewMenu main_menu = { main_str, main_sub };
  841.  
  842. struct TextAttr ta = { (UBYTE*) "topaz.font", 8,0,0 };
  843.  
  844.  
  845. /* Basic stuff for the test program.
  846.  */
  847. struct NewWindow nwin = {
  848.     50,20, 200,100, -1,-1, CLOSEWINDOW,
  849.     WINDOWCLOSE|WINDOWDRAG|ACTIVATE,
  850.     NULL,NULL, (UBYTE*) "Test the Menus", NULL,NULL,
  851.     0,0,0,0, WBENCHSCREEN
  852. };
  853.  
  854. #define OLIB(var,nam)    (var=OpenLibrary(nam,33L))
  855.  
  856. struct IntuitionBase *IntuitionBase;
  857. struct Window *mywin;
  858.  
  859.  
  860. struct Window *OpenWindow();
  861. void *OpenLibrary();
  862. void *GetMsg();
  863.  
  864.  
  865. main ()
  866. {
  867.     if (OLIB(IntuitionBase,"intuition.library")) {
  868.         if (mywin = OpenWindow (&nwin)) {
  869.             Body ();
  870.             CloseWindow (mywin);
  871.         }
  872.         CloseLibrary (IntuitionBase);
  873.     }
  874. }
  875.  
  876.  
  877. Body ()
  878. {
  879.     struct IntuiMessage *im;
  880.     struct Menu *m;
  881.  
  882.     if (!(m = GenMenu (&main_menu))) return;
  883.  
  884.     SetMenuStrip (mywin, m);
  885.  
  886.     /* Wait for the close window message.
  887.      */
  888.     while (!(im = (struct IntuiMessage *) GetMsg (mywin->UserPort)))
  889.         WaitPort (mywin->UserPort);
  890.     ReplyMsg (im);
  891.  
  892.     ReadMenuState (m);
  893.     ClearMenuStrip (mywin);
  894.     FreeMenu (m);
  895. }
  896.  
  897.  
  898. ReadMenuState (m)
  899.     struct Menu *m;
  900. {
  901.     struct MenuItem    *mi;
  902.  
  903.     /* Get the text style menu array and test for checkmarks.
  904.      */
  905.     mi = m[1].FirstItem[8].SubItem;
  906.     printf ("Text Style: ");
  907.     if (mi[0].Flags & CHECKED) printf ("Plain");
  908.     if (mi[1].Flags & CHECKED) printf ("Bold ");
  909.     if (mi[2].Flags & CHECKED) printf ("Italic ");
  910.     if (mi[3].Flags & CHECKED) printf ("Underline");
  911.     printf ("\n");
  912. }
  913. SHAR_EOF
  914. cat << \SHAR_EOF > mtst.uu
  915.  
  916. begin 644 mtst
  917. M```#\P`````````#``````````(```=@```!E@````$```/I```'8$[Z#*0AF
  918. M/4]287<@5&5X="XN+@!0<F]C97-S960@5&5X="XN+@!$<F%W:6YG+BXN`%!I+
  919. M8W1U<F4N+BX`3VQD(%-E='1I;F=S+BXN```A/51497AT+BXN`"$]1$1R87=I!
  920. M;F<N+BX`4&EC='5R92XN+@`A/4Y.97<N+BX`3W!E;@`A/5-3879E+BXN`%-AU
  921. M=F4@87,`4')I;G0N+BX`4V%V92!3971T:6YG<P!!8F]U="XN+@`M`"%B475I*
  922. M="XN+@`A*R$P,3$Q(3U04&QA:6X`(6,A,2$]0D)O;&0`(6,A,2$]24ET86QIW
  923. M8P`A8R$Q(3U556YD97)L:6YE```A/5%5;F1O`"T`(3U:1&5L971E`"$]6$-U]
  924. M=``A/4-#;W!Y`"$]5E!A<W1E`"T`4V5T($9O;G0N+BX`4V5T(%-T>6QE`"$]V
  925. M/DEN`"$]/$]U=``A/4U-86YU86P``"$K(71497AT`"$K(71,:6YE<P`A*R%T3
  926. M26UA9V5S`"$K(71";WAE<P`A*R%T3&%B96QS``!);G1E<FQA8V4`3F]N+6ENR
  927. M=&5R;&%C90!7;W)K8F5N8V@`6F]O;0`A/4%!=71O(%-C86QE`"T`(6,A=$-O@
  928. M;W)D:6YA=&5S`%9I<VEB;&4`+0!38W)E96X@0V]L;W)S+BXN`%-C<F5E;B!44
  929. M>7!E`%!L;W0N+BX`4V5T+BXN`$QA>2!I;BXN+@``(2LA,#$Q,3$Q,49U;&P@*
  930. M26UP=6QS90`A8R$Q,#$Q,3$Q(3TQ5V%R<"`Q`"%C(3$Q,#$Q,3$A/3)787)PY
  931. M(#(`(6,A,3$Q,#$Q,2$],U=A<G`@,P`A8R$Q,3$Q,#$Q(3TT5V%R<"`T`"%C*
  932. M(3$Q,3$Q,#$A/35787)P(#4`(6,A,3$Q,3$Q,%-P86-E($YO<FUA;`!3='5N3
  933. M`$MI;&P`36%I;0!"=7)N`$]V97)L;V%D`$EN969F96-T:79E`$)U<FX@3W5TZ
  934. M`$YE=R!#;W5R<V4`4W!E960`4W1A;F1A<F0@3W)B:70`5')A8W1O<B!"96%MQ
  935. M+BXN`$QO8VL@4&AA<V5R<P`M`")-86ME($ET(%-O+B(``$AA;6UE<@!38W)E,
  936. M=V1R:79E<@!#:&ES96P`2VYI9F4`1F5L="!096X`06ER($9R97-H96YE<@`MA
  937. M`$AA;6UE<B!3:7IE+BXN`%-C<F5W(%1Y<&4N+BX`4&EN92!38V5N="XN+@!2T
  938. M;W1A=&4N+BX`4W!I;BXN+@!4=7)N($%R;W5N9"XN+@!&;&EP($]U="XN+@!2&
  939. M86YD;VUI>F4N+BX`16YE<F=I>F4N+BX`4VEM<&QI9GD`0V]M<&QE>&EF>0!0A
  940. M<F]J96-T`$5D:70`1&ES<&QA>0!4;V]L<P!(96QM`$UO9&EF>0``=&]P87HN^
  941. M9F]N=```5&5S="!T:&4@365N=7,``$Y5``!(>``A2'H`.$ZZ&*103RE`A@9G=
  942. M)DAL@MY.NAD@6$\I0(8*9PQA*B\LA@I.NACV6$\O+(8&3KH8'EA/3EU.=6EN2
  943. M='5I=&EO;BYL:6)R87)Y`$Y5__A(;(+.3KH!&EA/*T#_^&8$3EU.=2\M__@O3
  944. M+(8*3KH8U%!/(&R&"B\H`%9.NA@>6$\K0/_\9A`@;(8*+R@`5DZZ&$Q83V#<Q
  945. M+RW__$ZZ&")83R\M__AA&%A/+RR&"DZZ&&183R\M__A.N@:P6$]@HDY5__P@!
  946. M;0`((F@`,"MI`2S__$AZ`&Y.N@P<6$\@;?_\""@````,9PI(>@!E3KH,!EA//
  947. M(&W__`@H````+F<*2'H`54ZZ"_!83R!M__P(*````%!G"DAZ`$5.N@O:6$\@,
  948. M;?_\""@```!R9PI(>@`W3KH+Q%A/2'H`-TZZ"[I83TY=3G5497AT(%-T>6QEC
  949. M.B``4&QA:6X`0F]L9"``271A;&EC(`!5;F1E<FQI;F4`"@``NP!.50``2.</Q
  950. M,"1M``A\`&`"4D8P!DC`Y8`@4DJP"`!F\"\286983R9`(`MF"G``3-\,\$Y=>
  951. M3G5Z`21J``1X`&`R2I)G*D*G0J<O"DZZ`L9/[P`,+@`P!,'\`!X@0-'+(4<`-
  952. M$DJ'9P1P`6`"<`#*0%"*4D2X1FW*2D5F#"\+3KH%>EA/<`!@J"`+8*1.50``S
  953. M2.<.,'P`8`)21C`&2,#E@"!M``A*L`@`9NY"IS`&P/P`'G(`,@`O`4ZZ%CA0D
  954. M3R1`(`IF"G``3-\,<$Y=3G5Z`'@`8&(P!,'\`!XF0-?*($M#[(,V<`8@V5'(W
  955. M__PPV3=%``0P!$C`Y8`@;0`(+S`(`$ZZ!?983\'\``I80#=```@P*P`(T'P`8
  956. M"MI`,`1(P.6`(&T`""=P"```#B!+T?P````>)HA21+A&;9HP!E-`P?P`'D*R^
  957. M"``@"F``_WQ.50``2.<`,"1M``A"ITAX`!1.NA624$\F0$J`9@IP`$S?#`!.(
  958. M74YU($M#[(,B(-D@V2#9(-D@V2\+3KH6-%A/,BH`"))`54$W00`$0J<P*@`("
  959. MD'P`$DC`+P`O+0`,3KH!:$_O``PE0``<9A!(>``4+PM.NA584$]P`&"D(&H`/
  960. M$B%+`!!P`6"83E4``$CG#``@;0`(#!``(68``2)2K0`((&T`"!`02(!(P&``<
  961. M`,H@;0`,".@````-8```^B!M``P`:``)``Q@``#L(&T`#`)H_S\`#"!M``P(*
  962. MZ``'``U@``#4(&T`#`)H_S\`#"!M``P`:`#```Q@``"\(&T`#`)H_^\`#&``#
  963. M`*X@;0`,`&@!`0`,8```H"!M``P(Z``"``U2K0`((&T`"")M``P34``:8```I
  964. M@G@`>@`@;0`(#!``,&<*(&T`"`P0`#%F'"!M``A2K0`($!!(@)!\`#`R!5)%X
  965. MXV!(P-B`8-`@;0`,(40`#E.M``A@/I"\````*V>*6X!GLE.`9ZZ0O`````QG(
  966. MB)"\````)6<`_S13@&<`_Q)3@&<`_UB0O`````IG`/\V78!G`/\*4JT`"&``5
  967. M_M8@+0`(3-\`,$Y=3G5.5?_V2.</,$)M__I@!%)M__HP+?_Z2,#E@"!M``@BV
  968. M4$JQ"`!FZ$*G,"W_^L#\`")R`#(`+P%.NA.F4$\D0$J`9@IP`$S?#/!.74YU5
  969. M?@!Z`&`@,`5(P.6`(&T`"")0('$(``P0`"UF!'`!8`)P`-Y`4D6Z;?_Z;=HP\
  970. M+?_ZD$=G-D*G,"W_^I!'P/P`%'(`,@`O`4ZZ$TI03R@`9AHP+?_ZP/P`(G(`F
  971. M,@`O`2\*3KH35E!/<`!@CDI'9U9"IS`'P/P`%'(`,@`O`4ZZ$Q103RM`__QFU
  972. M/#`M__K`_``B<@`R`"\!+PI.NA,>4$\P+?_ZD$=G&#`M__J01\#\`!1R`#(`B
  973. M+P$O!$ZZ$OY03W``8`#_-GX`>@!@``"@,`5(P.6`(&T`"")0('$(``P0`"UG)
  974. M``"&,`7!_``B)D#7RB!+0^R#5'`'(-E1R/_\,-DG1``2($1#[(,.(-D@V2#9K
  975. M(-D@V2\+,`5(P.6`(&T`"")0+S$(`$ZZ_4Y03R!$(4``#"\$3KH3*%A//`!8Q
  976. M1@@K``(`#6<$W'P`)0@K````#6<,($0&:``3``3<?``3O$=O`CX&V+P````47
  977. M4D6Z;?_Z;0#_7'H`8```H#`%P?P`(B9`U\HP!4C`Y8`@;0`((E`@<0@`#!``R
  978. M+6<F-VT`#@`$-VT`$@`&-T<`"#`L@MI40#=```HP*P`*2,#1K0`08$P@;?_\N
  979. M0^R#=B#9(-D@V2#9(-D@;?_\,`>0?``*,4``!"!+0^R#BG`'(-E1R/_\,-D@C
  980. M+0`05(`W0``&7*T`$"=M__P`$@:M````%/_\($O1_````"(FB%)%NFW_^FT`V
  981. M_UPP+?_Z4T#!_``B0K((`"!M``@K:``$__9F!B`*8`#]O'X!>@!@.C`%2,#ED
  982. M@"!M``@B4"!Q"``,$``M9R(@;?_V2I!G%B\M__8P!<'\`"+0BB\`3KK[>E!/5
  983. MSD!0K?_V4D6Z;?_Z;<!*1V8,+PIA4EA/<`!@`/UF(`I@`/U@3E4``$CG""!X&
  984. M`"1M``A@$DJJ`!)G""\J`!)A*%A/4D0D4B`*9NHP!,#\`!YR`#(`+P$O+0`(G
  985. M3KH0YE!/3-\$$$Y=3G5.5?_\2.</,"1M``A\`$*M__QZ`#@%)DI@3$JK`!QG@
  986. M""\K`!QAVEA/""L``0`-9R8N*P`22H9F`BP'4D0@1TJH`!!G$$AX`!0@1R\H,
  987. M`!!.NA"*4$]@#DJM__QF!BMK`!+__%)%)E,@"V:P2D1G%#`$P/P`%'(`,@`OQ
  988. M`2\&3KH07%!/2D5G%C`%P/P`%'(`,@`O`2\M__Q.NA!"4$\P!-!%P/P`(G(`7
  989. M,@`O`2\*3KH0+%!/3-\,\$Y=3G4@;P`$(`A*&&;\D<`@"%.`3G5A<$/LA@)%N
  990. M[(8"M<EF#C(\`!5K"'0`(L)1R?_\*4^&#BQX``0I3H822.>`@`@N``0!*6<06
  991. M2_H`"$ZN_^)@!D*G\U].<T/Z`"!.KOYH*4"&%F8,+CP``X`'3J[_E&`$3KH`Q
  992. M&E!/3G5D;W,N;&EB<F%R>0!)^0``?_Y.=4Y5```O"DAY``$``#`LA?C!_``&A
  993. M+P!.N@]:*4"&&E!/9A1"ITAY``$``$ZZ#QI03RYLA@Y.=2!LAAI":``$(&R&:
  994. M&C%\``$`$"!LAAHQ?``!``H@;(8.("R&#I"H``10@"E`AAX@;(8>(+Q-04Y85
  995. M0J=.N@\.)$!*J@"L6$]G+B\M``PO+0`(+PI.N@"N.7P``88B(&R&&@!H@```[
  996. M!"!LAAH`:(````I/[P`,8$)(:@!<3KH//$AJ`%Q.N@[R*4"&)"!LAB1*J``DD
  997. M4$]G$"!LAB0B:``D+Q%.N@X&6$\O+(8D+PI.N@)H*6R&)(8H4$].N@X&(&R&G
  998. M&B"`3KH.)B!LAAHA0``&9Q9(>`/M2'H`*DZZ#@(@;(8:(4``#%!/+RR&*#\LF
  999. MABQ.NO7@0F=.N@P@4$\D7TY=3G4J`$Y5``!(YPPP)&T`$"!M``A*J`"L9Q@@G
  1000. M;0`(("@`K.6`*``@1"`H`!#E@"9`8`0F;(7Z$!-(@$C`T*T`#%2`.4"&+D*G8
  1001. M,"R&+DC`+P!.N@WL*4"&,%!/9@A,WPPP3EU.=1`32(`Z`#\%($M2B"\(+RR&/
  1002. M,$ZZ`7XP!4C`($#1[(8P0_H!1!#99OP_+0`.+PHO+(8P3KH!.B!LAC!",%``?
  1003. M.7P``88L,`5(P-"LAC`F0%*+)$M/[P`4$!-(@#H`L'P`(&<8NGP`"6<2NGP`Y
  1004. M#&<,NGP`#6<&NGP`"F8$4HM@V`P3`"!M>@P3`")F+E*+($M2BQ`02(`Z`&<>U
  1005. M($I2BA"%NGP`(F80#!,`(F8$4HM@!D(J__]@`F#68#@@2U*+$!!(@#H`9R:ZB
  1006. M?``@9R"Z?``)9QJZ?``,9Q2Z?``-9PZZ?``*9P@@2E**$(5@SB!*4HI"$$I%W
  1007. M9@)3BU)LABQ@`/]:0A)"IS`LABQ20$C`Y8`O`$ZZ#,HI0(8H4$]F"$)LABQ@J
  1008. M`/[8>@`F;(8P8"0P!4C`Y8`@;(8H(8L(`"!+(`A*&&;\D<!3B#`(4D!(P-?`8
  1009. M4D6Z;(8L;=8P!4C`Y8`@;(8H0K`(`&``_I0@`#`\?_]@!#`O``P@;P`$2AAFN
  1010. M_%-((F\`"%-`$-E7R/_\9P)"$"`O``1.=4SO`P``!"`(,B\`#&`"$-E7R?_\4
  1011. M9P9206`"0AA1R?_\3G5.50``2.<.,"1M``A"ITAZ`(Y.N@Q<*4"&-%!/9@A,B
  1012. MWPQP3EU.=2!M``PB:``D+RD`!$ZZ#)0H`%A/9U)(>@!M($0O*``V3KH,9B9`<
  1013. M2H!03V<T2'@#[2\+3KH+;"P`4$]G)"`&Y8`J`"!%)6@`"`"D)48`G$AX`^U(5
  1014. M>@`X3KH+2"5``*!03R\$3KH,,EA/+RR&-$ZZ"WY"K(8T6$]@@&EC;VXN;&EBT
  1015. M<F%R>0!724Y$3U<`*@!.50``2&T`#"\M``A(>@1@3KH`F$_O``Q.74YU3E4`I
  1016. M`$CG""`D;0`.#&T`!``29@@@;0`(*!!@'$IM``QO#"!M``AP`#`0*`!@"B!M>
  1017. M``@P$$C`*`!";0`22FT`#&P01&T`#$J$;`A$A#M\``$`$C(M``Q(P2`$3KH#L
  1018. MD$'L@ZQ3BA2P```R+0`,2,$@!$ZZ`X8H`&;:2FT`$F<&4XH4O``M(`I,WP007
  1019. M3EU.=4Y5_R)(YP@P)&T`""9M``Q";?_Z*VT`$/_\($M2BQ`02(`X`&<``NZX3
  1020. M?``E9@`"S$(M_S`[?``!__@[?``@__8[?"<0__0@2U*+$!!(@#@`L'P`+68.$
  1021. M0FW_^"!+4HL0$$B`.`"X?``P9A`[?``P__8@2U*+$!!(@#@`N'P`*F88(&W_4
  1022. M_%2M__P[4/_R($M2BQ`02(`X`&`R0FW_\F`<,"W_\L'\``K01)!\`#`[0/_R;
  1023. M($M2BQ`02(`X`#`$4D!![(.^"#```@``9M2X?``N9EH@2U*+$!!(@#@`L'P`&
  1024. M*F88(&W__%2M__P[4/_T($M2BQ`02(`X`&`R0FW_]&`<,"W_],'\``K01)!\Y
  1025. M`#`[0/_T($M2BQ`02(`X`#`$4D!![(.^"#```@``9M0[?``"__"X?`!L9A(@.
  1026. M2U*+$!!(@#@`.WP`!/_P8!"X?`!H9@H@2U*+$!!(@#@`,`1(P&!Z.WP`"/_N8
  1027. M8!8[?``*_^Y@#CM\`!#_[F`&.WS_]O_N/RW_\$AM_S`_+?_N+RW__$ZZ_>0K(
  1028. M0/_J,"W_\$C`T:W__$_O``Q@7"!M__Q8K?_\(E`K2?_J(`E*&6;\D\!3B3M)T
  1029. M__!@2B!M__Q4K?_\.!!![?\O*TC_ZA"$8"B0O````&-GXE.`9Y*0O`````MG[
  1030. M`/]R68!GLE6`9P#_<%>`9P#_<F#,0>W_,)'M_^H[2/_P,"W_\+!M__1O!CMM8
  1031. M__3_\$IM__AG:"!M_^H,$``M9PH@;?_J#!``*V8N#&T`,/_V9B93;?_R(&W_'
  1032. MZE*M_^H0$$B`/P!.DK!\__]43V8*</],WPP03EU.=6`6/RW_]DZ2L'S__U1/^
  1033. M9@1P_V#D4FW_^C`M__)3;?_RL&W_\&[<0FW_[F`@(&W_ZE*M_^H0$$B`/P!.9
  1034. MDK!\__]43V8$</]@L%)M_^X@;?_J2A!G"C`M_^ZP;?_T;<XP+?_NT6W_^DIM"
  1035. M__AF*&`8/SP`($Z2L'S__U1/9@9P_V``_WA2;?_Z,"W_\E-M__*P;?_P;MI@B
  1036. M%C\$3I*P?/__5$]F!G#_8`#_4E)M__I@`/T(,"W_^F``_T)(YT@`0H1*@&H$;
  1037. M1(!21$J!:@9$@0I$``%A/DI$9P)$@$S?`!)*@$YU2.=(`$*$2H!J!$2`4D1*F
  1038. M@6H"1(%A&B`!8-@O`6$2(`$B'TJ`3G4O`6$&(A]*@$YU2.<P`$A!2D%F($A!_
  1039. M-@$T`$)`2$"`PR(`2$`R`H+#,`%"04A!3-\`#$YU2$$F`2(`0D%(04A`0D!TN
  1040. M#]"`TX&V@6($DH-20%'*__),WP`,3G5.50``2&R$5C\M``A.N@`(7$].74YU+
  1041. M3E4``"\$."T`""\M``H_!$ZZ`#"X?``*7$]F)"!M``H0*``,2(`(```'9Q0_#
  1042. M//__+RT`"DZZ`/1<3R@?3EU.=6#X3E4``"\*)&T`"B!2L>H`!&48,"T`",!\Z
  1043. M`/\_`"\*3KH`R%Q/)%].74YU(%)2DA`M``D0@$B`P'P`_V#H3E4``"\*0>R$G
  1044. M0"1(($K5_````!8O"&$06$]![(7XM<AEZB1?3EU.=4Y5``!(YP@@)&T`"'@`^
  1045. M(`IF"G#_3-\$$$Y=3G5**@`,9U`(*@`"``QG##\\__\O"F%2.`!<3Q`J``U(W
  1046. M@#\`3KH%'(A`""H``0`,5$]G"B\J``A.N@(N6$\(*@`%``QG$B\J`!).N@+`T
  1047. M+RH`$DZZ`A103T*20JH`!$*J``A"*@`,,`1@D$Y5__Y(YP@@)&T`"$'Z_T8IU
  1048. M2(8X""H`!``,9PIP_TS?!!!.74YU""H``@`,9S`@4I'J``@X"#\$+RH`"!`J_
  1049. M``U(@#\`3KH"@+!$4$]G$`CJ``0`#$*20JH`!'#_8,`,;?__``QF$`BJ``(`J
  1050. M#$*20JH`!'``8*A*J@`(9@@O"DZZ`)I83PQJ``$`$&8J&VT`#?__/SP``4AM/
  1051. M__\0*@`-2(`_`$ZZ`B*P?``!4$]FH#`M``Q@`/]J)*H`"#`J`!!(P-"J``@EK
  1052. M0``$".H``@`,(%)2DA`M``T0@$B`P'P`_V``_SY.50``+PI![(1`)$A**@`,-
  1053. M9QC5_````!9![(7XM<AE"'``)%].74YU8.)"DD*J``1"J@`((`I@ZDY5__PO6
  1054. M"B1M``@_/`0`3KH`P"M`__Q43V88-7P``0`0($K1_`````XE2``()%].74YU>
  1055. M-7P$```0".H``0`,)6W__``($"H`#4B`/P!.N@#B2D!43V<&`"H`@``,8,Y.=
  1056. M50``2.<`,"1LA@)@%"92("H`!%"`+P`O"DZZ!%903R1+(`IFZ$*LA@),WPP`3
  1057. M3EU.=4Y5```O"D'Z_\8I2(8\0J<@+0`(4(`O`$ZZ!``D0$J`4$]F"'``)%]."
  1058. M74YU)*R&`B5M``@`!"E*A@(@"E"`8.9.50``<``P+0`(+P!ALEA/3EU.=4Y5#
  1059. M``!(YP`PE\LD;(8"8`X@;0`(48BQRF<2)DHD4B`*9NYP_TS?#`!.74YU(`MGS
  1060. M!":28`0I4H8"("H`!%"`+P`O"DZZ`ZAP`%!/8-A.50``+PHP+0`(P?P`!B1`+
  1061. MU>R&&DIM``AM#C`M``BP;(7X;`1*DF8..7P``H9`</\D7TY=3G4P+0`(P?P`8
  1062. M!B!LAAHO,`@`3KH"QDJ`6$]G!'`!8`)P`SE4``"\M``A.N@*02H!83V8.&
  1063. M3KH"FCE`AD!P_TY=3G5P`Ϥ``$CG#"`X+0`(3KH`<#`$P?P`!B1`U>R&-
  1064. M&DI$;0JX;(7X;`1*DF80.7P``H9`</],WP0P3EU.=3`J``3`?``#9@HY?``%"
  1065. MAD!P_V#D<``P+0`.+P`O+0`*+Q).N@)F*@"PO/____]/[P`,9@Q.N@(:.4"&+
  1066. M0'#_8+@@!6"T3E7__$AX$`!"ITZZ`MXK0/_\"```#%!/9Q)*;(8B9@@@+?_\E
  1067. M3EU.=4ZZ``9P`&#T3E4``$AX``1(>@`<3KH!\"\`3KH"`C\\``%.N@`.3^\`)
  1068. M#DY=3G5>0PH`3E4``$JLACAG!B!LACA.D#\M``A.N@`(5$].74YU3E7__"\$Y
  1069. M,"T`"$C`*T#__$JLAAIG*'@`8`H_!$ZZ`/Y43U)$N&R%^&WP,"R%^,'\``8OE
  1070. M`"\LAAI.N@'T4$]*K(8\9P8@;(8\3I!*K(7^9PHO+(7^3KH!:%A/2JR&0F<(U
  1071. M(&R&0B"LAD9*K(9*9PHO+(9*3KH!A%A/2JR&3F<*+RR&3DZZ`7183TJLAE)G%
  1072. M"B\LAE).N@%D6$]*K(969PHO+(963KH!5%A/+'@`!`@N``0!*6<4+PU+^@`*A
  1073. M3J[_XBI?8`9"I_-?3G-*K(8D9C!*K(8P9R@P+(8N2,`O`"\LAC!.N@%,,"R&(
  1074. M+%)`2,#E@"\`+RR&*$ZZ`3A/[P`08`Y.N@$B+RR&)$ZZ`5Y83R`M__PN;(8.4
  1075. M3G4H'TY=3G5.50``2.<.(#@M``@P!,'\``8D0-7LAAI*1&T*N&R%^&P$2I)FY
  1076. M$#E\``*&0'#_3-\$<$Y=3G4(*@`'``1F""\23KH`"EA/0I)P`&#B(B\`!"QLA
  1077. MAA9.[O_<(B\`!"QLAA9.[O^"(B\`!"QLAA9.[O^X+&R&%D[N_\HL;(863N[_=
  1078. M?"(O``0L;(863N[_*$SO``8`!"QLAA9.[O_B+&R&%D[N_\1.^@`"(B\`!"QLH
  1079. MAA9.[O^F3.\`#@`$+&R&%D[N_]!(YP$$3.\@@``,+&R&$DZN_Y1,WR"`3G5._
  1080. M^@`"(F\`!"QLAA).[OYB3OH``DSO``,`!"QLAA).[O\Z(F\`!"QLAA).[O[:G
  1081. M+&R&$D[N_WQ.^@`"(F\`!"`O``@L;(823N[_+D[Z``(@;P`$+&R&$D[N_HQ.7
  1082. M^@`"+&R&$B)O``0@+P`(3N[]V$[Z``(B;P`$+&R&$D[N_H9,[P`#``0L;(82J
  1083. M3N[^SD[Z``(@;P`$+&R&$D[N_H!,[P,```0L;(8T3N[_H"!O``0L;(8T3N[_>
  1084. MIB!O``0L;(8T3N[_LB!O``0L;(8&3N[_RB!O``0L;(8&3N[_N"!O``0L;(8&5
  1085. M3N[^MB!O``0L;(8&3N[_-$SO`P``!"QLA@9.[O[X``````/L`````0````$`?
  1086. M``T:`````````_(```/J```!@`````0````3````)0```#`````[````````Q
  1087. M`$P```!7````90````````!P````>@```'\```"*````D@```)L```"I````1
  1088. ML@```+0`````````````````````````````````````````&```````````^
  1089. M`````````````````````````````````````````+X```#.````V@```.@`.
  1090. M````````^@```0(```$$```!#@```14```$=```!)@```2@```$T````````*
  1091. M`````````````````````````````````````````````````````````````
  1092. M`````)`````````!/@```40```%+`````````58```%?```!:0```70```%^U
  1093. M`````````8H```&4```!H@````````&L```!L0```;\```'!```!T0```=D`0
  1094. M``';```![`````````$$``````````````````````````````$4````````C
  1095. M```````````!+`````````'X```"`````@<````````"$@```BD```(]```"Q
  1096. M40```F4```)Y```"C0````````*D```"J0```JX```*S```"N````L$```+-$
  1097. M`````````M8```+A```"YP```O8```,&```#$P```Q4````````!D```````D
  1098. M``&@``````````````````````````````'````````````````````#)```)
  1099. M`RL```,W```#/@```T0```--```#6P```UT```-L```#>@````````.(```#X
  1100. MD@```YH```.I```#M0```\(```/.```#UP````````/B```#Z@```^\```/W!
  1101. M```#_0``!`(`````````*````%````"D````S````3P```%@```",```````^
  1102. M``'@```"`````EP````````"@````IP```0*``@````R`!0`R`!D__\```(`I
  1103. M```0"@`````````````$%@```````````````````````0(``````@`!```"\
  1104. MU````````````P````````$```+4```%G`````````````````````H``0``:
  1105. M````````````````````````````````````4@``````````````````````2
  1106. M```````````!``(``@````````````````````4`````````T```````````:
  1107. M````````````````,#$R,S0U-C<X.6%B8V1E9@```"`@("`@("`@(#`P,#`PR
  1108. M("`@("`@("`@("`@("`@("`@D$!`0$!`0$!`0$!`0$!`0`P,#`P,#`P,#`Q`(
  1109. M0$!`0$!`"0D)"0D)`0$!`0$!`0$!`0$!`0$!`0$!`0%`0$!`0$`*"@H*"@H"(
  1110. M`@("`@("`@("`@("`@("`@("`D!`0$`@``````````````````$``````0``(
  1111. M```````````````````!`0````$``````````````````````0(````!````'
  1112. M`````````````````````````````````````````````````````````````
  1113. M`````````````````````````````````````````````````````````````
  1114. M`````````````````````````````````````````````````````````````
  1115. M`````````````````````````````````````````````````````````````
  1116. M`````````````````````````````````````````````````````````````
  1117. M`````````````````````````````````````````````````````````````
  1118. M`````````````````````````````````````````````````````````````
  1119. M`````````````````````````````````````````````````````````````
  1120. M`````````````````````!0``````````````^P````7`````0```%@```!H;
  1121. M````_````6````%X```!B````@````((```"(````IP```*@```"I````J@`=
  1122. M``*L```"L````K0```*\```"P````L0```+,```"T````Q0```,H````9```B
  1123. M````````````!`````@````,````$````!@````<````(````"@````L````0
  1124. M,````#0````X````/````$````!$````2````)````"4````F````)P```"D@
  1125. M````J````*P```"P````M````+@```"\````P````,0```$$```!"````0P`+
  1126. M``$4```!&````1P```$@```!)````2P```$P```!-````3P```%````!1```G
  1127. M`4@```%,```!4````50```%8```!D````90```&8```!H````:0```&H```!$
  1128. MK````;````&T```!N````<````'$```!R````<P```'0```!U````=@```'@'
  1129. M```!Y````>@```'L```!\````?0```'X```",````C0```(X```"/````D``\
  1130. M``)$```"2````DP```)0```"5````EP```)@```"9````F@```)L```"<```V
  1131. M`G0```)X```"@````H0```*(```"C````I````*4```"U````O8```,L````U
  1132. 1`````_(```/K`````0```_*(A
  1133. ``
  1134. end
  1135. size 9692
  1136. SHAR_EOF
  1137. #    End of shell archive
  1138. exit 0
  1139. -- 
  1140. Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
  1141. Have five nice days.
  1142.